/*
 * Project: book
 * 
 * File Created at 2017年9月18日
 * 
 * Copyright 2016 CMCC Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * ZYHY Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license.
 */
package com.whb.book.common.interceptor;

import java.lang.reflect.Method;
import java.net.URI;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.whb.book.common.ActionResponse;
import com.whb.book.common.Constants;
import com.whb.book.common.ResMsg;

/**
 * @Type PermissionInterceptor.java
 * @Desc 
 * @author wanghb
 * @date 2017年9月18日 下午4:06:08
 * @version 
 */
@Aspect //切面
@Component("PermissionInterceptor")
public class PermissionInterceptor {

    private static Logger logger = LoggerFactory.getLogger(PermissionInterceptor.class);
    
    private SessionCache sessionCache;

    public void setSessionCache(SessionCache sessionCache) {
        this.sessionCache = sessionCache;
    }

    public static final String EXEC = "execution(* com.whb.book.web.*Action.*(..))"
            + "&& !execution(* com.whb.book.web.*Action.get*(..))"
            + "&& !execution(* com.whb.book.web.*Action.set*(..))";

    @Pointcut(EXEC) //切入点。匹配连接点（Joinpoint）的断言。通知和一个切入点表达式关联，并在满足这个切入点的连接点上运行。切入点表达式如何和连接点匹配是AOP的核心：Spring缺省使用AspectJ切入点语法。
    public void interceptor() {

    }

    @Around("interceptor()") //通知 包括“around”、“before”和“after”等
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        //ProceedingJoinPoint 连接点 。一个连接点 总是 代表一个方法的执行
        //环绕通知
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        PermissionAuth pa = method.getAnnotation(PermissionAuth.class);
        if (pa == null) {
            logger.info("Action {} 未配置PermissionAuth Annotation", method.getName());
            return point.proceed();
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        String referer = request.getHeader("referer");
        logger.info("请求来源referer={}", referer);
        if (StringUtils.isBlank(referer)) {
            throw new RuntimeException("非法访问");
        }else{
            URI uri = URI.create(referer);
            if(!Constants.DOMAIN.equalsIgnoreCase(uri.getHost())){
                throw new RuntimeException("非法访问");
            }
        }
        CookieManager cm = new CookieManager(request, null);
        UserSession us = sessionCache.getLoginCache(cm);
        if (us == null) {// 未登录
            // 前端定义的统一参数
            if ("true".equalsIgnoreCase(request.getParameter("isAsync"))) {
                ActionResponse actionResponse = new ActionResponse();
                actionResponse.setStatus(ResMsg.LOGIN_TIMEOUT_ERROR.getCode());
                actionResponse.setMessage(ResMsg.LOGIN_TIMEOUT_ERROR.getMsg());
                actionResponse.setRedirectInResult("/");
                return actionResponse;
            } else {
                throw new RuntimeException("请先登录");
            }
        } else {
            // 登录用户，判断角色
            if (pa.role() != Constants.NO_SPECIAL_ROLE && us.getRole() != pa.role()) {// 实际角色和配置角色不等，无权访问
                if ("true".equalsIgnoreCase(request.getParameter("isAsync"))) {
                    // post请求，弹框提示
                    ActionResponse actionResponse = new ActionResponse();
                    actionResponse.setStatus(ResMsg.NO_ROLE_ERROR.getCode());
                    actionResponse.setMessage(ResMsg.NO_ROLE_ERROR.getMsg());
                    return actionResponse;
                } else {
                    // get请求，跳错误页统一展示
                    throw new RuntimeException("权限不足，无法访问");
                }
            }
        }
        return point.proceed();
    }

}

/**
 * Revision history
 * -------------------------------------------------------------------------
 * 
 * Date Author Note
 * -------------------------------------------------------------------------
 * 2017年9月18日 wanghb create
 */
